package com.skt.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.skt.config.CacheConstants;
import com.skt.domain.DTO.request.ChangePasswordRequest;
import com.skt.domain.DTO.request.UpdateProfileRequest;
import com.skt.domain.ENUM.AccountStatus;
import com.skt.domain.PO.User;
import com.skt.domain.VO.UserVO;
import com.skt.exception.*;
import com.skt.mapper.UserMapper;
import com.skt.security.LoginUser;
import com.skt.service.ProfileService;
import com.skt.utils.RedisUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.UUID;
import java.util.concurrent.TimeUnit;


@RequiredArgsConstructor
@Service
@Slf4j
public class ProfileServiceImpl extends ServiceImpl<UserMapper, User> implements ProfileService {


    private final UserMapper userMapper;
    private final RedisUtil redisUtil;
    private final BCryptPasswordEncoder passwordEncoder;


    /**
     * 获取当前登录用户的完整信息
     * 身份认证 → ID验证 → 缓存查询 → 状态验证 → 数据脱敏 → 审计日志
     *
     * @return 脱敏后的用户信息VO对象
     * @throws BusinessException 用户不存在或状态异常时抛出业务异常
     * @throws AuthException 系统级异常时抛出认证异常
     */
    @Override
    public UserVO getCurrentUserInfo() {
        log.info("开始获取当前用户信息");

        try {
            // 1. 从安全上下文获取当前用户ID
            Long currentUserId = extractCurrentUserId();

            // 2. 验证用户ID有效性
            validateUserId(currentUserId);

            // 3. 多级缓存查询(L1:Redis查询 L2:MySQL查询)
            User user = retrieveUserWithCache(currentUserId);

            // 4. 验证用户状态
            validateUserAccountStatus(user);

            // 5. 缓存到Redis
            cacheUserToRedis(currentUserId, user);

            // 6. PO转VO并脱敏处理
            UserVO userVO = UserVO.from(user);
            performDataDesensitization(userVO);

            log.info("获取当前用户信息成功: userId={}", currentUserId);
            return userVO;

        } catch (BusinessException e) {
            log.warn("获取当前用户信息失败: error={}", e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("获取当前用户信息系统异常", e);
            throw AuthException.of(AuthErrorCode.SYSTEM_ERROR);
        }
    }


    /**
     * 更新当前用户个人资料
     *
     * 该方法负责处理用户个人资料的更新操作，包含完整的业务校验和数据一致性保证：
     * 1. 身份验证与权限校验
     * 2. 参数校验与业务规则验证
     * 3. 分布式锁防止并发修改
     * 4. 数据更新与缓存一致性维护
     * 5. 审计日志记录
     *
     * @param updateRequest 更新请求参数
     * @return 更新后的用户信息VO对象
     * @throws UserException 业务校验失败时抛出
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserVO updateUserProfile(UpdateProfileRequest updateRequest) {
        log.info("开始更新用户个人资料: {}", updateRequest.getUsername());

        String lockKey = null;
        String requestId = UUID.randomUUID().toString();

        try {
            // 1. 获取用户ID
            Long userId = extractCurrentUserId();

            // 2. ID基础格式校验
            validateUserId(userId);

            // 3. 参数预处理
            preprocessAndValidateRequest(updateRequest);

            // 4. 获取分布式锁防止并发修改
            lockKey = "update_user_profile_lock:" + userId;
            boolean lockAcquired = redisUtil.tryLock(lockKey, requestId, 30, TimeUnit.SECONDS);

            if (!lockAcquired) {
                log.warn("更新用户信息操作频繁: userId={}, username={}", userId, updateRequest.getUsername());
                throw UserException.of(UserErrorCode.USER_OPERATION_CONFLICT);
            }
            log.info("成功获取用户资料更新锁: userId={}", userId);

            // 5. 查询现有用户信息
            User existingUser = retrieveUserWithCache(userId);

            // 6. 验证用户账户状态
            validateUserAccountStatus(existingUser);

            // 7. 业务规则深度验证（唯一性校验等）
            validateBusinessRules(updateRequest, existingUser);

            // 8. 执行数据更新
            User updatedUser = executeUserUpdate(updateRequest, existingUser);

            // 9. 清理用户缓存保证数据一致性
            clearUserCache(userId);

            // 10. 记录审计日志
            logUserProfileUpdate(existingUser, updatedUser, userId);

            // 11. 转换为VO并脱敏处理
            UserVO userVO = UserVO.from(updatedUser);
            performDataDesensitization(userVO);

            log.info("更新用户资料成功: userId={}", userId);
            return userVO;

        } catch (UserException | AuthException e) {
            log.warn("更新用户资料业务异常: userId={}, error={}",
                    extractCurrentUserIdSafely(), e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("更新用户资料系统异常: userId={}", extractCurrentUserIdSafely(), e);
            throw UserException.userUpdateFailed();
        } finally {
            // 12. 释放分布式锁
            if (lockKey != null) {
                try {
                    redisUtil.releaseLock(lockKey, requestId);
                    log.debug("释放用户资料更新锁: lockKey={}", lockKey);
                } catch (Exception e) {
                    log.error("释放分布式锁异常: lockKey={}", lockKey, e);
                }
            }
        }
    }


    /**
     * 修改密码
     * @param changePasswordRequest
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void changePassword(ChangePasswordRequest changePasswordRequest) {
        // 1. 获取用户ID
        Long userId = extractCurrentUserId();

        // 2. 多级缓存查询(L1:Redis查询 L2:MySQL查询)
        User user = retrieveUserWithCache(userId);

        // 3. 验证用户状态是否正常
        validateUserAccountStatus(user);
        log.info("开始修改密码: username={}", user.getUsername());

        // 4. 请求参数校验
        validateChangePassword(changePasswordRequest);

        // 5. 旧密码验证
        validateOldPassword(changePasswordRequest, user);

        // 6. 密码强度验证
        validatePasswordStrength(changePasswordRequest.getNewPassword());

        // 7. 密码加密
        String encryptedPassword = passwordEncoder.encode(changePasswordRequest.getNewPassword());

        // 8. 数据库更新
        updateUserPassword(userId, encryptedPassword);

        // 9. 清理缓存
        clearUserCache(userId);

        // 10. 记录简单日志
        log.info("用户密码修改成功: userId={}", userId);
    }

    /**
     * 验证旧密码
     */
    private void validateOldPassword(ChangePasswordRequest changePasswordRequest, User user) {
        if (!passwordEncoder.matches(changePasswordRequest.getOldPassword(), user.getPassword())) {
            log.warn("旧密码验证失败: userId={}", user.getId());
            throw UserException.of(UserErrorCode.OLD_PASSWORD_INCORRECT);
        }
    }

    /**
     * 请求参数校验
     */
    private void validateChangePassword(ChangePasswordRequest changePasswordRequest) {
        // 新密码不能与旧密码相同
        if (changePasswordRequest.getOldPassword().equals(changePasswordRequest.getNewPassword())) {
            throw UserException.of(UserErrorCode.NEW_PASSWORD_SAME_AS_OLD);
        }

        // 新密码要与确认密码相同
        if (!changePasswordRequest.getNewPassword().equals(changePasswordRequest.getConfirmPassword())) {
            throw UserException.of(UserErrorCode.PASSWORD_CONFIRM_MISMATCH);
        }
    }

    /**
     * 密码强度验证
     */
    private void validatePasswordStrength(String password) {
        if (password.length() < 8 || password.length() > 24) {
            throw UserException.of(UserErrorCode.PASSWORD_STRENGTH_WEAK);
        }

        // 密码复杂度：必须包含字母和数字
        boolean hasLetter = password.matches(".*[a-zA-Z]+.*");
        boolean hasDigit = password.matches(".*\\d+.*");

        if (!hasLetter || !hasDigit) {
            throw UserException.of(UserErrorCode.PASSWORD_STRENGTH_WEAK);
        }
    }

    /**
     * 更新用户密码
     */
    private void updateUserPassword(Long userId, String encryptedPassword) {
        User updateUser = new User();
        updateUser.setId(userId);
        updateUser.setPassword(encryptedPassword);
        updateUser.setUpdatedAt(LocalDateTime.now());

        int result = userMapper.updateById(updateUser);
        if (result <= 0) {
            log.error("密码更新失败: userId={}", userId);
            throw UserException.of(UserErrorCode.PASSWORD_CHANGE_FAILED);
        }
    }



    /**
     * 执行用户数据更新操作
     */
    private User executeUserUpdate(UpdateProfileRequest updateRequest, User existingUser) {
        log.info("开始执行用户数据更新: userId={}", existingUser.getId());

        try {
            // 构建更新对象
            User updateUser = new User();
            updateUser.setId(existingUser.getId());

            // 只更新有变化的字段
            if (StringUtils.isNotBlank(updateRequest.getUsername()) &&
                    !updateRequest.getUsername().equals(existingUser.getUsername())) {
                updateUser.setUsername(updateRequest.getUsername());
            }

            if (StringUtils.isNotBlank(updateRequest.getRealName()) &&
                    !updateRequest.getRealName().equals(existingUser.getRealName())) {
                updateUser.setRealName(updateRequest.getRealName());
            }

            if (StringUtils.isNotBlank(updateRequest.getPhone()) &&
                    !updateRequest.getPhone().equals(existingUser.getPhone())) {
                updateUser.setPhone(updateRequest.getPhone());
            }

            if (StringUtils.isNotBlank(updateRequest.getEmail()) &&
                    !updateRequest.getEmail().equals(existingUser.getEmail())) {
                updateUser.setEmail(updateRequest.getEmail());
            }

            // 设置更新时间
            updateUser.setUpdatedAt(LocalDateTime.now());

            // 执行更新
            int updateCount = userMapper.updateById(updateUser);
            if (updateCount == 0) {
                log.warn("用户数据更新失败: userId={}", existingUser.getId());
                throw UserException.userUpdateFailed();
            }

            // 重新查询获取完整的最新数据
            User updatedUser = userMapper.selectById(existingUser.getId());
            if (updatedUser == null) {
                throw UserException.userNotFound();
            }

            log.info("用户数据更新成功: userId={}", existingUser.getId());
            return updatedUser;

        } catch (UserException e) {
            throw e;
        } catch (Exception e) {
            log.error("执行用户数据更新异常: userId={}", existingUser.getId(), e);
            throw UserException.userUpdateFailed();
        }
    }

    /**
     * 清理用户相关缓存
     */
    private void clearUserCache(Long userId) {
        try {
            // 清理用户详情缓存
            redisUtil.delete(CacheConstants.USER_ENTITY_KEY_PREFIX + userId);
            // 清理用户信息相关的其他缓存
            redisUtil.delete(CacheConstants.USER_SESSIONS_KEY_PREFIX + userId);
            log.info("用户缓存清理完成: userId={}", userId);
        } catch (Exception e) {
            log.error("清理用户缓存异常: userId={}", userId, e);
            // 缓存清理失败不影响主流程，但需要记录告警
        }
    }

    /**
     * 记录用户资料更新审计日志
     */
    private void logUserProfileUpdate(User oldUser, User newUser, Long operatorId) {
        try {
            // 记录详细的修改日志
            log.info("用户资料更新审计 - 操作人: {}, 用户ID: {}, 修改内容: [用户名: {}->{}, 真实姓名: {}->{}, 手机号: {}->{}, 邮箱: {}->{}]",
                    operatorId, oldUser.getId(),
                    oldUser.getUsername(), newUser.getUsername(),
                    oldUser.getRealName(), newUser.getRealName(),
                    oldUser.getPhone(), newUser.getPhone(),
                    oldUser.getEmail(), newUser.getEmail());

            // 可以在这里添加更详细的审计日志记录逻辑
            // 比如记录到数据库的审计日志表
        } catch (Exception e) {
            log.warn("记录用户资料更新审计日志异常", e);
        }
    }

    /**
     * 安全地获取当前用户ID（用于异常处理中的日志记录）
     */
    private Long extractCurrentUserIdSafely() {
        try {
            return extractCurrentUserId();
        } catch (Exception e) {
            return -1L; // 返回默认值，避免异常处理中再抛异常
        }
    }

    /**
     * 业务规则深度验证（核心校验）
     */
    private void validateBusinessRules(UpdateProfileRequest updateRequest, User existingUser) {
        log.info("开始业务规则深度验证: userId={}", existingUser.getId());

        // 1. 用户名唯一性校验
        validateUsernameUniqueness(updateRequest.getUsername(), existingUser);

        // 2. 邮箱唯一性校验
        validateEmailUniqueness(updateRequest.getEmail(), existingUser);

        // 3. 手机号唯一性校验
        validatePhoneUniqueness(updateRequest.getPhone(), existingUser);

        log.info("业务规则验证通过: userId={}", existingUser.getId());
    }

    /**
     * 用户名唯一性校验
     */
    private void validateUsernameUniqueness(String newUsername, User existingUser) {
        if (newUsername == null || newUsername.equals(existingUser.getUsername())) {
            return; // 未修改用户名，跳过校验
        }

        boolean usernameExists = userMapper.existsByUsernameExcludeId(newUsername, existingUser.getId());
        if (usernameExists) {
            log.warn("用户名已存在: username={}, userId={}", newUsername, existingUser.getId());
            throw UserException.usernameAlreadyExists();
        }
    }

    /**
     * 邮箱唯一性校验
     */
    private void validateEmailUniqueness(String newEmail, User existingUser) {
        if (newEmail == null || newEmail.equals(existingUser.getEmail())) {
            return; // 未修改邮箱，跳过校验
        }

        boolean emailExists = userMapper.existsByEmailExcludeId(newEmail, existingUser.getId());
        if (emailExists) {
            log.warn("邮箱已被绑定: email={}, userId={}", newEmail, existingUser.getId());
            throw UserException.emailAlreadyExists();
        }
    }

    /**
     * 手机号唯一性校验
     */
    private void validatePhoneUniqueness(String newPhone, User existingUser) {
        if (newPhone == null || newPhone.equals(existingUser.getPhone())) {
            return; // 未修改手机号，跳过校验
        }

        boolean phoneExists = userMapper.existsByPhoneExcludeId(newPhone, existingUser.getId());
        if (phoneExists) {
            log.warn("手机号已被使用: phone={}, userId={}", newPhone, existingUser.getId());
            throw UserException.phoneAlreadyExists();
        }
    }

    /**
     * 参数预处理与基础校验
     */
    private void preprocessAndValidateRequest(UpdateProfileRequest updateRequest) {
        // 参数预处理：去除前后空格
        if (updateRequest.getUsername() != null) {
            updateRequest.setUsername(updateRequest.getUsername().trim());
        }
        if (updateRequest.getRealName() != null) {
            updateRequest.setRealName(updateRequest.getRealName().trim());
        }
        if (updateRequest.getEmail() != null) {
            updateRequest.setEmail(updateRequest.getEmail().trim().toLowerCase());
        }
        if (updateRequest.getPhone() != null) {
            updateRequest.setPhone(updateRequest.getPhone().trim());
        }

        // 基础格式校验
        if (StringUtils.isBlank(updateRequest.getUsername())) {
            throw UserException.of(UserErrorCode.USER_DATA_VALIDATION_FAILED, "用户名不能为空");
        }

        if (updateRequest.getUsername().length() < 2) {
            throw UserException.usernameTooShort();
        }

        if (StringUtils.isNotBlank(updateRequest.getEmail()) &&
                !updateRequest.getEmail().matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$")) {
            throw UserException.of(UserErrorCode.USER_DATA_VALIDATION_FAILED, "邮箱格式不正确");
        }

        if (StringUtils.isNotBlank(updateRequest.getPhone()) &&
                !updateRequest.getPhone().matches("^1[3-9]\\d{9}$")) {
            throw UserException.of(UserErrorCode.USER_DATA_VALIDATION_FAILED, "手机号格式不正确");
        }
    }





    /**
     * 获取客户端真实IP - 网络层工具方法
     * 从HTTP请求中提取客户端真实IP，支持代理场景
     *
     * 获取优先级：
     * 1. X-Forwarded-For（代理转发IP）
     * 2. X-Real-IP（真实IP）
     * 3. RemoteAddr（直接连接IP）
     *
     * @return String 客户端真实IP地址
     */
    private String getClientIP() {
        try {
            HttpServletRequest request = ((ServletRequestAttributes)
                    RequestContextHolder.getRequestAttributes()).getRequest();

            // 1. 从代理头获取（nginx等反向代理）
            String ip = request.getHeader("X-Forwarded-For");
            if (StringUtils.isNotEmpty(ip) && !"unknown".equalsIgnoreCase(ip)) {
                return ip.split(",")[0].trim(); // 取第一个IP（真实客户端IP）
            }

            // 2. 从真实IP头获取
            ip = request.getHeader("X-Real-IP");
            if (StringUtils.isNotEmpty(ip) && !"unknown".equalsIgnoreCase(ip)) {
                return ip;
            }

            // 3. 直接获取远程地址（最后兜底）
            return request.getRemoteAddr();
        } catch (Exception e) {
            log.warn("获取客户端IP失败", e);
            return "unknown"; // 异常情况返回未知标识
        }
    }

    /**
     * 用户信息脱敏处理
     * 对敏感字段进行脱敏，保护用户隐私
     *
     * @param userVO 用户视图对象
     */
    private void performDataDesensitization(UserVO userVO) {
        if (userVO == null) {
            return;
        }

        log.debug("开始用户信息脱敏处理: userId={}", userVO.getId());

        try {
            userVO.setPhone(desensitizePhone(userVO.getPhone()));
            userVO.setEmail(desensitizeEmail(userVO.getEmail()));
            userVO.setRealName(desensitizeRealName(userVO.getRealName()));

            log.debug("用户信息脱敏完成: userId={}", userVO.getId());
        } catch (Exception e) {
            log.warn("用户信息脱敏处理异常，跳过脱敏: userId={}", userVO.getId(), e);
        }
    }

    /**
     * 手机号脱敏：保留前3位和后4位，中间用*代替
     * 支持11位标准手机号
     */
    private String desensitizePhone(String phone) {
        if (phone == null || phone.length() != 11) {
            return phone; // 非标准手机号不脱敏
        }
        return phone.substring(0, 3) + "****" + phone.substring(7);
    }

    /**
     * 邮箱脱敏：保留用户名前2位，@符号及域名
     * 支持标准邮箱格式
     */
    private String desensitizeEmail(String email) {
        if (email == null || !email.contains("@")) {
            return email; // 非标准邮箱不脱敏
        }

        int atIndex = email.indexOf("@");
        if (atIndex <= 2) {
            return "***" + email.substring(atIndex); // 用户名过短
        }

        return email.substring(0, 2) + "****" + email.substring(atIndex);
    }

    /**
     * 真实姓名脱敏：保留首尾字符，中间用*代替
     * 支持2-10个字符的姓名
     */
    private String desensitizeRealName(String realName) {
        if (realName == null || realName.length() < 2) {
            return realName; // 姓名过短不脱敏
        }

        if (realName.length() == 2) {
            return realName.charAt(0) + "*"; // 2字姓名
        }

        return realName.charAt(0) + "*" + realName.charAt(realName.length() - 1);
    }

    /**
     * 多级缓存查询用户信息
     * 查询顺序：Redis缓存 → 数据库
     *
     * @param userId 用户ID
     * @return user
     * @throws AuthException 用户不存在、账户状态异常或系统异常时抛出
     */
    private User retrieveUserWithCache(Long userId) {
        log.debug("开始多级缓存查询: userId={}", userId);

        try {
            // 1. Redis缓存查询
            User user = getUserFromRedisCache(userId);
            if (user != null) {
                log.debug("Redis缓存命中: userId={}", userId);
                return user;
            }

            log.debug("Redis缓存未命中，查询数据库: userId={}", userId);

            // 2. 数据库查询（兜底）
            user = getUserFromDatabase(userId);
            if (user == null) {
                log.warn("用户不存在: userId={}", userId);
                throw AuthException.of(AuthErrorCode.USER_NOT_EXIST);
            }

            log.debug("数据库查询成功并缓存: userId={}", userId);
            return user;

        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("多级缓存查询异常: userId={}", userId, e);
            throw AuthException.of(AuthErrorCode.SYSTEM_ERROR);
        }
    }

    /**
     * 从Redis缓存中查询用户信息
     * 如果缓存读取异常，自动降级到数据库查询
     *
     * @param userId 用户ID
     * @return 用户实体对象，缓存未命中或异常时返回null
     */
    private User getUserFromRedisCache(Long userId) {
        try {
            String cacheKey = "user:entity:" + userId;
            Object cachedData = redisUtil.get(cacheKey);
            return (User) cachedData;
        } catch (Exception e) {
            log.warn("Redis缓存读取异常，降级到数据库查询: userId={}", userId, e);
            return null;
        }
    }

    /**
     * 从数据库中查询用户信息
     * 直接调用MyBatis Plus的selectById方法
     *
     * @param userId 用户ID
     * @return 用户实体对象，未找到时返回null
     */
    private User getUserFromDatabase(Long userId) {
        log.debug("查询数据库用户信息: userId={}", userId);
        return userMapper.selectById(userId);
    }

    /**
     * 验证用户账户状态
     * 检查用户账户是否处于启用状态
     *
     * @param user 用户实体对象
     * @throws AuthException 账户状态异常时抛出ACCOUNT_DISABLED错误
     */
    private void validateUserAccountStatus(User user) {
        if (user.getAccountStatus() != AccountStatus.ENABLED) {
            log.warn("用户账户状态异常: userId={}, status={}", user.getId(), user.getAccountStatus());
            throw AuthException.of(AuthErrorCode.ACCOUNT_DISABLED);
        }
    }

    /**
     * 将用户信息缓存到Redis
     * 设置30分钟过期时间，防止缓存永久存储
     *
     * @param userId 用户ID
     * @param user 用户实体对象
     */
    private void cacheUserToRedis(Long userId, User user) {
        try {
            String cacheKey = "user:entity:" + userId;
            // 缓存30分钟
            redisUtil.set(cacheKey, user, 30, TimeUnit.MINUTES);
            log.debug("用户信息缓存成功: userId={}", userId);
        } catch (Exception e) {
            log.warn("缓存写入失败: userId={}", userId, e);
        }
    }


    /**
     * 验证用户ID格式有效性
     * 该方法仅进行基础格式验证，不涉及数据库查询，确保高性能
     *
     * @param userId 待验证的用户ID
     * @throws AuthException 当用户ID为null、小于等于0时抛出 USER_ID_INVALID 异常
     */
    private void validateUserId(Long userId) {
        if (userId == null || userId <= 0) {
            throw AuthException.of(AuthErrorCode.USER_ID_INVALID);
        }
    }

    /**
     * 从Spring Security上下文中提取当前认证用户的ID
     * 该方法会验证认证信息的存在性和有效性，确保只有合法用户能够访问
     *
     * @return 当前登录用户的ID
     * @throws AuthException 当认证信息不存在时抛出 TOKEN_MISSING 异常
     * @throws AuthException 当Principal类型不匹配时抛出 TOKEN_INVALID 异常
     */
    private Long extractCurrentUserId() {
        // 从SecurityContext获取当前认证信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null) {
            // 认证信息不存在，说明Token缺失或未认证
            throw AuthException.of(AuthErrorCode.TOKEN_MISSING);
        }

        // 获取认证主体信息
        Object principal = authentication.getPrincipal();
        Long userId = null;

        // 验证Principal类型是否为自定义的LoginUser对象
        if (principal instanceof LoginUser loginUser) {
            // 类型匹配，安全提取用户ID
            userId = loginUser.getUserId();
        } else {
            // Principal类型不匹配，说明Token无效或格式错误
            throw AuthException.of(AuthErrorCode.TOKEN_INVALID);
        }

        // 返回提取到的用户ID（调用方需要进一步验证格式）
        return userId;
    }
}